package com.ext.aic.ui;

import android.content.Intent;
import android.os.Bundle;
import android.text.SpannableString;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.View;

import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

import com.ext.aic.R;
import com.ext.aic.apis.content.ContentContinueRequest;
import com.ext.aic.apis.content.ContentPublishRequest;
import com.ext.aic.apis.content.ContentUpdatePublishRequest;
import com.ext.aic.beans.Attachment;
import com.ext.aic.beans.CustomMedia;
import com.ext.aic.beans.DraftInfo;
import com.ext.aic.beans.ImageMeta;
import com.ext.aic.beans.params.ContentContinueParams;
import com.ext.aic.beans.params.ContentGenerateParams;
import com.ext.aic.beans.params.ContentPublishParams;
import com.ext.aic.beans.response.ContentContinueResponse;
import com.ext.aic.beans.response.ContentDetailResponse;
import com.ext.aic.beans.response.ContentGenerateResponse;
import com.ext.aic.beans.response.ContentPublishResponse;
import com.ext.aic.components.RectCornerSpan;
import com.ext.aic.components.SharePanelBottomPopup;
import com.ext.aic.constants.EBusConstants;
import com.ext.aic.databinding.AiGenerateLayoutBinding;
import com.ext.aic.databinding.EditDetailLayoutBinding;
import com.ext.aic.enums.ContentType;
import com.ext.aic.enums.EditNineSource;
import com.ext.aic.enums.EditType;
import com.ext.aic.enums.ShareType;
import com.ext.aic.events.AttachmentUploadCallback;
import com.ext.aic.events.OnWriteBackContinueContentListener;
import com.ext.aic.fragment.NinePictureFragment;
import com.ext.aic.handler.AttachmentHandler;
import com.ext.aic.handler.BubblePositionHandler;
import com.ext.aic.handler.DraftHandler;
import com.ext.aic.handler.EditSpanHandler;
import com.ext.aic.handler.ShareHandler;
import com.ext.aic.handler.TypeWriterHandler;
import com.ext.aic.utils.FilteringUtils;
import com.ext.aic.utils.FragmentUtils;
import com.ext.aic.utils.RTEditUtils;
import com.ext.aic.utils.ToastyUtils;
import com.ext.aic.utils.UserUtils;
import com.ext.aic.utils.XPopupUtils;
import com.eyinfo.android_pure_utils.HandlerManager;
import com.eyinfo.android_pure_utils.ObjectManager;
import com.eyinfo.android_pure_utils.ebus.EBus;
import com.eyinfo.android_pure_utils.ebus.SubscribeEBus;
import com.eyinfo.android_pure_utils.events.Action0;
import com.eyinfo.android_pure_utils.events.RunnableParamsN;
import com.eyinfo.android_pure_utils.utils.JsonUtils;
import com.eyinfo.android_pure_utils.utils.ObjectJudge;
import com.eyinfo.android_pure_utils.utils.PixelUtils;
import com.onegravity.rteditor.api.format.RTFormat;

import java.io.File;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentLinkedDeque;

public class EditDetailActivity extends BaseActivity {

    private EditDetailLayoutBinding binding;
    private AiGenerateLayoutBinding aiGenerateLayoutBinding;
    private ContentPublishParams publishParams;
    private TypeWriterHandler typeWriterHandler = new TypeWriterHandler();
    private BubblePositionHandler bubblePositionHandler = new BubblePositionHandler();
    private EditSpanHandler spanHandler = new EditSpanHandler();
    //存储上传图片的元数据
    private Map<Long, ImageMeta> imageMetaMap = new HashMap<>();
    private Deque<CustomMedia> uploadDeque = new ConcurrentLinkedDeque<>();
    //内容详情数据
    private EditType editType;
    private ContentGenerateParams generateParams;
    private ContentGenerateResponse generateResponse;
    private ContentDetailResponse detail;

    private NinePictureFragment pictureFragment;

    private boolean isChangeImage = false; //是否修改了图片

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        View view = View.inflate(this, R.layout.edit_detail_layout, null);
        binding = EditDetailLayoutBinding.bind(view);
        bindView();
        setContentView(binding.getRoot());
        EBus.getInstance().registered(this, String.valueOf(hashCode()));
        initData();
    }

    private void bindView() {
        binding.topView.titleTv.setText(R.string.edit_detail);
        binding.topView.backRl.setOnClickListener(this::onBackClick);
        binding.returnIv.setOnClickListener(this::onUndoClick);
        binding.mainBtn.setOnClickListener(this::onMainClick);
        binding.cancelBtn.setOnClickListener(this::onCancelClick);
        binding.clearIv.setOnClickListener(this::onClearClick);
        spanHandler.fitCursor(binding.editRte);
        ViewCompat.setOnApplyWindowInsetsListener(binding.editDetailRl, (v, insets) -> {
            int imeHeight = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom;
            boolean isKeyboardVisible = imeHeight > 0;
            changeKeyboardEvent(isKeyboardVisible);
            return insets;
        });

        int screenWidth = ObjectManager.getScreenWidth(this);
        int maxWidth = screenWidth - PixelUtils.dip2px(this, 24);
        pictureFragment = new NinePictureFragment(maxWidth, false);
        pictureFragment.setAttachments(null);
        pictureFragment.setNineSource(EditNineSource.details);
        FragmentUtils.getInstance().bind(getSupportFragmentManager(), R.id.images_fl, pictureFragment);
        bubblePositionHandler.initBubble(this, binding.editRte);

        //AI写作视图
        View view = View.inflate(this, R.layout.ai_generate_layout, null);
        view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
        aiGenerateLayoutBinding = AiGenerateLayoutBinding.bind(view);
        aiGenerateLayoutBinding.spanEditRte.setKeyListener(null);
    }

    public void onBackClick(View view) {
        if (hasChangeItems()) {
            changeConfirm();
        } else {
            finish();
        }
    }

    private void changeConfirm() {
        String title = getString(R.string.tip);
        String content = getString(R.string.change_content_save_confirm);
        XPopupUtils.getInstance().showConfirmDialog(this, title, content, false, () -> {
            DraftHandler.getInstance().saveDraft(buildDraftData());
            finish();
        });
    }

    private DraftInfo buildDraftData() {
        DraftInfo draftInfo = new DraftInfo();
        if (editType == EditType.editing) {
            draftInfo.setId((long) detail.getId().hashCode());
            draftInfo.setContentId(detail.getId());
        }
        draftInfo.setImages(JsonUtils.toJson(imageMetaMap.values()));
        draftInfo.setTitle(binding.titleEt.getText().toString());
        draftInfo.setContent(binding.editRte.getText(RTFormat.HTML));
        draftInfo.setUpdateTime(System.currentTimeMillis());
        return draftInfo;
    }

    private void changeKeyboardEvent(boolean isKeyboardVisible) {
        HandlerManager.getInstance().postDelayed(new RunnableParamsN<Object>() {
            @Override
            public void run(Object... objects) {
                reacquireTheCursor();
                bubblePositionHandler.showBubbleAtCursor(binding.editRte);
            }
        }, 500);
    }

    private void initData() {
        //注册编辑器工厂类
        RTEditUtils.getInstance().registerEditor(this, binding.editRte);
        //初始化数据
        initParams();
        //绑定数据
        if (editType == EditType.creation) {
            binding.titleEt.setText(generateResponse.getTitle());
            String html = FilteringUtils.getInstance().html(generateResponse.getContent());
            typeWriterHandler.startAutoType(binding.editRte, html);
        } else {
            List<Attachment> attachments = detail.getAttachments();
            pictureFragment.bindAttachmentDataEvent(attachments);
            if (!ObjectJudge.isNullOrEmpty(attachments)) {
                for (Attachment attachment : attachments) {
                    ImageMeta imageMeta = new ImageMeta();
                    imageMeta.setUrl(attachment.getFileUrl());
                    imageMeta.setAttachmentId(attachment.getId());
                    long id = attachment.getId().hashCode();
                    imageMetaMap.put(id, imageMeta);
                }
            }

            binding.titleEt.setText(detail.getTitle());
            String html = FilteringUtils.getInstance().html(detail.getBody());
            typeWriterHandler.startAutoType(binding.editRte, html);
        }
    }

    private void initParams() {
        Intent intent = getIntent();
        if (intent == null) {
            return;
        }
        Bundle extras = intent.getExtras();
        if (extras == null) {
            return;
        }
        editType = EditType.getEditType(extras.getString("creationType"));
        if (editType == EditType.editing || editType == EditType.referenceCreation) {
            detail = (ContentDetailResponse) extras.getSerializable("detail");
        } else if (editType == EditType.creation) {
            generateParams = (ContentGenerateParams) extras.getSerializable("generateParams");
            generateResponse = (ContentGenerateResponse) extras.getSerializable("generateResult");
        }
    }

    public void onClearClick(View view) {
        binding.titleEt.setText("");
    }

    public void onUndoClick(View view) {
        RTEditUtils.getInstance().undo();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        typeWriterHandler.destroy();
    }

    @SubscribeEBus(receiveKey = EBusConstants.aiWritePrompt)
    public void onAiWriteGenerateEvent(String prompt) {
        reacquireTheCursor();
        bubblePositionHandler.showBubbleAtCursor(binding.editRte);
        if (TextUtils.isEmpty(prompt)) {
            return;
        }
        ContentContinueParams contentContinueParams = getContentContinueParams(prompt);
        contentContinueRequest.request(this, this, contentContinueParams);
    }

    private ContentContinueParams getContentContinueParams(String prompt) {
        ContentContinueParams contentContinueParams = new ContentContinueParams();
        contentContinueParams.setUserId(UserUtils.getInstance().getUserId());
        contentContinueParams.setOriginalContent(binding.editRte.getText(RTFormat.HTML));
        contentContinueParams.setDescription(prompt);
        return contentContinueParams;
    }

    private ContentContinueRequest contentContinueRequest = new ContentContinueRequest() {
        @Override
        protected void onContentContinueSuccess(ContentContinueResponse response) {
            String content = response.getContent();
            if (TextUtils.isEmpty(content)) {
                ToastyUtils.getInstance().show(getString(R.string.ai_generate_busy));
            } else {
                OnWriteBackContinueContentListener contentListener = bubblePositionHandler.getWriteBackContinueContentListener();
                if (contentListener != null) {
                    contentListener.onWriteBack(content);
                }
            }
        }
    };

    @SubscribeEBus(receiveKey = EBusConstants.insertContinueContent)
    public void onInsertContinueContentEvent(String content) {
        SpannableString spannableString = spanHandler.buildSpannableString(binding.editRte, content);
        RectCornerSpan aiGenerateSpan = spanHandler.buildAiGenerateSpan(EditDetailActivity.this);
        spanHandler.bindSpan(spannableString, aiGenerateSpan);
        spanHandler.insertEdit(binding.editRte, spannableString);
    }

    @SubscribeEBus(receiveKey = EBusConstants.giveUpAiWriteGenerate)
    public void onGiveUpEvent() {
        reacquireTheCursor();
        bubblePositionHandler.showBubbleAtCursor(binding.editRte);
    }

    private void reacquireTheCursor() {
        int cursorPos = binding.editRte.getSelectionStart();
        binding.editRte.setSelection(cursorPos);
        binding.editRte.requestFocus();
        binding.editRte.setCursorVisible(true);
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        Boolean status = spanHandler.fitDelete(binding.editRte, keyCode, event);
        if (status == null) {
            return super.onKeyDown(keyCode, event);
        }
        return status;
    }

    public void onMainClick(View v) {
        if (!publishVerify()) {
            return;
        }
        SharePanelBottomPopup sharePanelBottomPopup = new SharePanelBottomPopup(this);
        sharePanelBottomPopup.setOnShareClick(this::onSharePlatformClick);
        XPopupUtils.getInstance().showBottomDialog(this, sharePanelBottomPopup);
    }

    private void preparePublishInfo() {
        //标题
        publishParams.setTitle(binding.titleEt.getText().toString());
        //内容
        publishParams.setContentType(ContentType.markdown);
        publishParams.setBody(binding.editRte.getText(RTFormat.HTML));
        //附件
        List<String> attachmentIds = new ArrayList<>();
        for (Map.Entry<Long, ImageMeta> entry : imageMetaMap.entrySet()) {
            ImageMeta meta = entry.getValue();
            attachmentIds.add(meta.getAttachmentId());
        }
        publishParams.setAttachmentIds(attachmentIds);
    }

    private boolean publishVerify() {
        publishParams = new ContentPublishParams();
        preparePublishInfo();
        if (TextUtils.isEmpty(publishParams.getTitle())) {
            ToastyUtils.getInstance().show(getString(R.string.title_empty_tip));
            return false;
        }
        if (TextUtils.isEmpty(publishParams.getBody())) {
            ToastyUtils.getInstance().show(getString(R.string.article_empty_tip));
            return false;
        }
        List<String> attachmentIds = publishParams.getAttachmentIds();
        if (ObjectJudge.isNullOrEmpty(attachmentIds)) {
            ToastyUtils.getInstance().show(getString(R.string.no_attachment_tip));
            return false;
        }
        return true;
    }

    public void onSharePlatformClick(ShareType shareType) {
        boolean isStation = true;
        if (shareType == ShareType.WeChat) {
            isStation = false;
            ShareHandler shareHandler = new ShareHandler();
            shareHandler.share(this);
        }
        if (editType == EditType.editing) {
            contentUpdatePublishRequest.request(this, this, detail.getId(), publishParams, isStation);
        } else {
            contentPublishRequest.request(this, this, publishParams, isStation);
        }
    }

    private ContentUpdatePublishRequest contentUpdatePublishRequest = new ContentUpdatePublishRequest() {
        @Override
        protected void onContentUpdatePublishSuccess(ContentPublishResponse result) {
            publishSuccess();
        }
    };

    private ContentPublishRequest contentPublishRequest = new ContentPublishRequest() {
        @Override
        protected void onContentPublishSuccess(ContentPublishResponse result) {
            publishSuccess();
        }
    };

    private void publishSuccess() {
        ToastyUtils.getInstance().show(getString(R.string.publish_success));
        EBus.getInstance().post(EBusConstants.finishCreate);
        EBus.getInstance().post(EBusConstants.switchMainTab, 0);
        EBus.getInstance().post(EBusConstants.refreshContentList);
        EBus.getInstance().post(EBusConstants.refreshMyPublishList);
        finish();
    }

    //回退到原页面
    public void onCancelClick(View v) {
        if (hasChangeItems()) {
            changeConfirm();
        } else {
            finish();
        }
    }

    //检测是否包含变更项
    private boolean hasChangeItems() {
        return checkImageChange() || checkTitleChange() || checkContentChange();
    }

    private boolean checkContentChange() {
        String text = binding.editRte.getText(RTFormat.HTML);
        if (editType == EditType.creation) {
            return !TextUtils.isEmpty(text);
        }
        return !TextUtils.equals(text, detail.getBody());
    }

    private boolean checkTitleChange() {
        String title = binding.titleEt.getText().toString();
        if (editType == EditType.creation) {
            return !TextUtils.isEmpty(title);
        }
        return !TextUtils.equals(title, detail.getTitle());
    }

    private boolean checkImageChange() {
        if (editType == EditType.creation) {
            return !imageMetaMap.isEmpty();
        } else {
            return isChangeImage;
        }
    }

    @SubscribeEBus(receiveKey = EBusConstants.delImage)
    public void onDelImageEvent(Long id) {
        imageMetaMap.remove(id);
        this.isChangeImage = true;
    }

    @SubscribeEBus(receiveKey = EBusConstants.singleAiGenerateImage)
    public void onSingleAIGenerateImageEvent(CustomMedia media, AttachmentUploadCallback<Long> callback) {
        uploadDeque.add(media);
        uploadImageDeque(callback);
    }

    @SubscribeEBus(receiveKey = EBusConstants.selectedImageList)
    public void onSelectImageEvent(List<CustomMedia> images, AttachmentUploadCallback<Long> callback) {
        this.isChangeImage = true;
        for (CustomMedia media : images) {
            if (imageMetaMap.containsKey(media.getId())) {
                continue;
            }
            uploadDeque.add(media);
        }
        uploadImageDeque(callback);
    }

    @SubscribeEBus(receiveKey = {EBusConstants.reUploadImage})
    public void onReUploadImageEvent(CustomMedia media, AttachmentUploadCallback<Long> callback) {
        if (imageMetaMap.containsKey(media.getId())) {
            return;
        }
        uploadDeque.add(media);
        uploadImageDeque(callback);
    }

    private void uploadImageDeque(AttachmentUploadCallback<Long> callback) {
        if (uploadDeque.isEmpty()) {
            return;
        }
        CustomMedia media = uploadDeque.poll();
        File file = new File(media.getRealPath());
        AttachmentHandler<Long> attachmentHandler = new AttachmentHandler<>(new Action0() {
            @Override
            public void call() {
                uploadImageDeque(callback);
            }
        });
        attachmentHandler.setUploadCallback(callback);
        attachmentHandler.upload(this, this, media.getFileName(), file, media.getId());
    }

    @SubscribeEBus(receiveKey = EBusConstants.attachmentUpdateSuccess)
    public void onAttachmentUpdateSuccess(Long value, String resourceName, String url, String realPath, String attachmentId) {
        System.out.println("成功：" + attachmentId);
        ImageMeta meta = imageMetaMap.get(value);
        if (meta == null) {
            imageMetaMap.put(value, new ImageMeta(url, attachmentId));
        } else {
            meta.setUrl(url);
            meta.setAttachmentId(attachmentId);
        }
    }

    @SubscribeEBus(receiveKey = EBusConstants.addImageDialog)
    public void onAddImageDialogEvent() {
        bubblePositionHandler.hideBubble();
    }
}
